/**
 * 时间轴
 */
type TimeLineParamsType = {
    reviewNum: number,
    MouseDownfn: Function,
    MouseUpfn: Function,
    CustomReMindLabelfn: Function,
    level: number,
    stepLength: number,
    timeSwitchContent: Function,
    CanvasConfigParams: Partial<CanvasConfigParamsType>,
    baseDate: Date,
    isCanvas: boolean
}

type GradientModeType = 'linear' | 'radial' | 'conic'
type CanvasConfigParamsType = {
    fontSize: string,
    scale_fontColor: string,
    scale_strokeColor: string,
    scale_lineWidth: number,
    scale_lineLength: number,
    tl_Height: number,
    tl_strokeColor: string,
    tl_strokeWidth: number,
    tl_fillColor: string,
    pg_fillColor: string,
    pg_gradientMode: GradientModeType,
    pg_gradientColors: string[],
    isGradient: boolean,
    tl_radius: number
}

export class useTimeLine {
    /**
     * 基时间
     * @description 如果没有则使用当前时间 
     */
    baseDate: Date | null = null
    /**
     * 时间数组
     */
    DateArray: string[] = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
    /**
     * 记录单位的数组 ["号","周","月","年"]
     */
    UnitArray: string[] = ["号", "周", "年", "年"]
    /**
     * 是否使用吸附效果
     */
    isAdsorb = false
    /**
     * 记录是否是初次加载 默认：是
     */
    #isInitLoad: boolean = true;
    /**
     * 当前显示时间轴的级别,默认：1
     */
    TimeLevel: number = 1;
    /**
     * 最外层的元素元素
     */
    ParentNode: HTMLElement | null;
    /**
     * 需要显示未来几天的数据
     */
    ReviewNum: number = 10;
    /**
     * 每个时间段需要的长度
     */
    TimeSlotWidth: number = 0
    /**
     * 每个时间段又分出多少间隔，默认：24
     */
    TimeSlotInterval: number = 60;
    /**
     * 时间段中每个间隔的长度
     */
    TimeSlotIntervalWidth: number = 0;
    /**
     * 保存当前时间进度
     */
    CurrentTimeProgress: number = 0;
    /**
     * 时间轴的步长
     */
    TimeStepLength = 1;
    /**
     * 时间轴移动的速度
     */
    TimeMoveSpeed: number = 2000;
    /**
     * 保存当前的移动进度
     */
    CurrentDay: number = 0;
    /**
     * 要显示的宏观文本数组--就是时间轴中最高级的显示单位
     */
    MacroTextArray: string[] = []
    /**
     * 要显示的微观数组
     */
    DateTextArray: number[] = []
    /**
     * 当前的canvas对象
     */
    _CanvasContent: CanvasRenderingContext2D | null = null
    /**
     * 是否使用canvas做时间轴
     */
    isCanvas = false;
    /**
     * 计算进度条时左边距-不用动
     */
    #CanvasMarginLeft = 60;
    /**
     * 时间轴的路径对象
     */
    TimeLinePath: Path2D | null = null;
    /**
     * 参数配置对象
     *  fontSize: 时间轴下方提示标尺的字体大小,
     *  scale_fontColor: 时间轴下方提示标尺的字体颜色
        scale_strokeColor: 标尺线的颜色,
        scale_lineWidth: 标尺线的宽度,
        scale_lineLength: 标尺线的高度,
        tl_Height: 时间轴的高度--进度条背景板,
        tl_strokeColor: 绘制时间轴时的线颜色 - 此属性必须配合tl_strokeWidth属性一起使用,
        tl_strokeWidth: 绘制时间轴时的线宽,
        tl_fillColor: 绘制时间轴时的填充颜色,
        pg_fillColor: 进度条的颜色
        pg_gradientMode: 进度条的渐变色的模式,
        pg_gradientColors: ['#cd1919', '#1977cd', '#f70da2'],
        isGradient: 是否使用渐变色
        tl_radius: 时间轴的边缘弧度
     */
    CanvasConfigParams: CanvasConfigParamsType = {
        fontSize: '',
        scale_fontColor: '#fff',
        scale_strokeColor: '',
        scale_lineWidth: 0,
        scale_lineLength: 5,
        tl_Height: 10,
        tl_strokeColor: '',
        tl_strokeWidth: 0,
        tl_fillColor: '',
        pg_fillColor: '',
        pg_gradientMode: 'radial',
        pg_gradientColors: ['#cd1919', '#1977cd', '#f70da2'],
        isGradient: false,
        tl_radius: 20
    }
    /**
     * 时间轴与鼠标交互时的元素
     */
    time_progressbar_tooltip: HTMLElement | null = null;
    /**
     * 覆盖在时间轴元素上方
     */
    t_progressbar: HTMLElement | null = null;
    /**
     * 自动播放按钮的点击状态回调
     * @param {*} flag  点击状态 播放：true 停止：false
     * @param {*} target 当前的元素
     */
    autoPlayClickStatus: Function | null = null;
    /**
     * 点击的状态
     */
    autoClickStatus: boolean = true;
    /**
     * 往自动播放按钮元素中添加元素的方法
     */
    timeSwitchContent: Function | null = null;
    /**
     * @description tooltip更换显示dom
     * @description tip:请返回string形式的dom
     * @param {object} e macro:最宏观的显示单位 day:中等显示单位 date:最小显示单位
     */
    setTooltipElementFn: Function | null = null;
    /**
     * 自定义时间轴底部的显示内容
     * @param {object} macro 当前的宏远显示单位
     * @param {object} secondary 当前二级显示单位  
     */
    CustomReMindLabelfn: Function | null = null;
    /**
     * 鼠标点下的回调方法
     */
    MouseDownfn: Function | null = null;
    /**
     * 鼠标松开的回调方法
     */
    MouseUpfn: Function | null = null
    /**
     * 生成时间轴
     * @param eleId 最外层的id 
     * @param reviewNum 要显示的天数
     * @param level 可选参数- 显示的层级
     * @returns useTimeLine
     */
    constructor(eleId: string, params: Partial<TimeLineParamsType>) {
        this.ParentNode = this.getById(eleId);

        if (!this.ParentNode) return this;

        this.init(params);

        return this;
    }
    init(params?: Partial<TimeLineParamsType>) {

        this.setGlobalConfigs(params)
        // 根据层级编辑展示信息数组
        this.useTimeShowTextByLevel()
        // 如果不是第一次加载--先销毁先前添加的事件
        this.DestoryTimeLine(this.#isInitLoad)
        // 往父元素中添加内容
        this.ParentNode?.appendChild(this.createElement() as HTMLDivElement)
        // 添加时间轴底部的信息展示框
        this.MakeReMindElement()
        // 添加鼠标事件
        this.addEventMouse()
        // 开关添加点击事件
        this.SwitchAddClick();

        this.ParentNode && this.ElementAddProxy(this.ParentNode)

        // 改变是否初次加载的值，变为false
        this.#isInitLoad = false;
    }
    /**
     * @param {*} params
     */
    setGlobalConfigs(params?: Partial<TimeLineParamsType>) {
        if (!params) return false;
        let { reviewNum, MouseDownfn, MouseUpfn, CustomReMindLabelfn, level, stepLength, timeSwitchContent, CanvasConfigParams, baseDate, isCanvas } = params;

        this.ReviewNum = reviewNum || this.ReviewNum;

        this.TimeLevel = level !== void 0 ? level : this.TimeLevel

        this.TimeStepLength = stepLength || this.TimeStepLength

        this.CustomReMindLabelfn = CustomReMindLabelfn instanceof Function ? CustomReMindLabelfn : null
        this.timeSwitchContent = timeSwitchContent instanceof Function ? timeSwitchContent : null;
        this.MouseDownfn = MouseDownfn instanceof Function ? MouseDownfn : null;
        this.MouseUpfn = MouseUpfn instanceof Function ? MouseUpfn : null;

        this.CanvasConfigParams = { ...this.CanvasConfigParams, ...CanvasConfigParams }

        this.baseDate = baseDate || this.baseDate || new Date();

        this.isCanvas = typeof isCanvas === "boolean" ? isCanvas : this.isCanvas || false;

    }
    /**
     * 按照显示级别来给时间轴设置显示文本
     */
    useTimeShowTextByLevel(level?: number) {
        let l = level ? level : this.TimeLevel;

        switch (l) {
            case 0:
                this.setDateTextArrayZore()
                // 一个小时有60分钟 
                this.TimeSlotInterval = 60;
                break;
            case 1:
                this.setDateTextArrayOne()
                // 一天有24小时
                this.TimeSlotInterval = 24;
                break;
            case 2:
                this.setDateTextArrayTwo()
                // 一月有30天，但是每个月有特殊性
                this.TimeSlotInterval = 30;
                break;
            case 3:
                this.setDateTextArrayThree()
                // 一月有30天，但是每个月有特殊性
                this.TimeSlotInterval = 12;
                break;
            default:
                throw new Error("当前显示设置级别不合理")
                break;
        }
    }
    ElementAddProxy(target: HTMLElement) {
        if (!target) return false;
        let self = this;
        // let observer = new MutationObserver((mutationList) => {
        // 	observer.disconnect()
        // 	console.log("html元素尺寸发生变化：", mutationList)
        //     self.init()
        // })
        // observer.observe(target, { attributes: true, subtree:true,characterData:true, attributeFilter: ['style'], attributeOldValue: true })
        // // 观察目标节点的变化
        const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                if (mutation.attributeName === 'style') {
                    observer.disconnect()
                    self.init()
                }
            });
        });
        const config = {
            attributes: true,  //监听元素的属性有没有变化
            attributeFilter: ['style'],
            characterData: true,
        };
        observer.observe(target, config);
    }
    /**
     * @description 鼠标是否可以拖动时间轴的条件
     * @description true:允许
     * @description false:禁止
     */
    TimeMouseDownFlag = false;
    // 为时间轴添加鼠标相应的事件
    addEventMouse() {
        let time_progressbar = this.getByClass("TimeLineProgressbar")
        if (!time_progressbar || time_progressbar.length == 0) return false;
        // 因为使用addEventListener来绑定事件，所以使用bind来更改this的指向
        (time_progressbar[0] as HTMLElement).addEventListener("mousedown", this.Time_MouseDown.bind(this))
        window.addEventListener("mousemove", this.WindowMouseMove_time.bind(this))
        window.addEventListener("mouseup", this.WindowMouseUp_time.bind(this))
        return true;
    }
    /**
     * window上的鼠标移动事件
     */
    WindowMouseMove_time(e: MouseEvent) {
        let self = this;
        if (!self.TimeMouseDownFlag) return false;
        e.preventDefault()
        this.#currentTargetOffset && self.updataElementStatus(e.pageX - this.#currentTargetOffset.left)
    }
    /**
     * window上的鼠标松开事件
     */
    WindowMouseUp_time(e: MouseEvent) {
        this.MouseUpfn && this.MouseUpfn(e)
        this.TimeMouseDownFlag = false;
    }
    #currentTargetOffset: { width: number, height: number, top: number, left: number } | null = null;
    /**
     * 时间轴上的鼠标按下事件
     */
    Time_MouseDown(e: MouseEvent) {
        let self = this;
        // 判断点击位置是否在路径内
        if (!this.isPointInPath(this.TimeLinePath, e.offsetX, e.offsetY)) return false;
        this.MouseDownfn && this.MouseDownfn(e)
        self.TimeMouseDownFlag = true;
        self.#currentTargetOffset = (e.currentTarget as HTMLElement)?.getBoundingClientRect();
        e.preventDefault()
        self.updataElementStatus(e.offsetX)
    }
    // 给时间轴的开关添加点击事件
    SwitchAddClick() {
        let self = this;
        let time_switch = this.getByClass("time_switch")[0] as HTMLDivElement;
        if (!time_switch) {
            setTimeout(() => {
                self.SwitchAddClick()
            }, 1000)
            return false;
        }
        if (time_switch == null) return false;
        time_switch.addEventListener("click", this.timeSwitchClickHandle.bind(this))
        return true;
    }
    timeSwitchClickHandle(e: MouseEvent) {
        this.autoUpdateTimeStatus(this.autoClickStatus);
        this.autoPlayClickStatus instanceof Function && this.autoPlayClickStatus(this.autoClickStatus, e.currentTarget, e)
        this.autoClickStatus = !this.autoClickStatus;
    }
    /**
     * 创建指定的元素
     */
    createElement() {

        if (!this.ParentNode) return false;

        let { width, height } = this.ParentNode.getBoundingClientRect();

        // 最外层的元素
        let timeLine = document.createElement("div");
        timeLine.classList.add('timeLine')
        // 控制时间轴的开关
        let time_switch = document.createElement("div");
        time_switch.classList.add('time_switch')
        this.timeSwitchContent && (time_switch.innerHTML = this.timeSwitchContent(time_switch))
        timeLine.appendChild(time_switch)

        // 时间轴线的外层元素
        let time_content = document.createElement("div");
        time_content.classList.add('time_content')

        !this.isCanvas && time_content.classList.add('time_content_flex')
        timeLine.appendChild(time_content)

        // 最下面的问题提示元素--周一--周二
        let time_progressbar_remind = document.createElement("div");
        time_progressbar_remind.classList.add('time_progressbar_remind')
        // 时间轴与鼠标交互时的元素
        this.time_progressbar_tooltip = document.createElement("div");
        this.time_progressbar_tooltip.classList.add('time_progressbar_tooltip')
        // 时间轴线
        let time_progressbar;
        if (this.isCanvas) {
            time_progressbar = document.createElement("canvas");
            this._CanvasContent = time_progressbar.getContext("2d");
            time_progressbar.classList.add('TimeLineProgressbar')
            time_progressbar.width = width - 60;
            time_progressbar.height = height;
            this.drawTimeLineByCanvas();
        } else {
            time_progressbar = document.createElement("div");
            time_progressbar.classList.add('time_progressbar')
            time_progressbar.classList.add('TimeLineProgressbar')
            // 覆盖在时间轴元素上方
            this.t_progressbar = document.createElement("div");
            this.t_progressbar.classList.add('t_progressbar')
            time_progressbar.appendChild(this.t_progressbar)
        }

        time_content.appendChild(this.time_progressbar_tooltip)
        time_content.appendChild(time_progressbar)
        time_content.appendChild(time_progressbar_remind)

        return timeLine;
    }
    /**
    * 绘制canvas时间轴
    */
    drawTimeLineByCanvas(progress = 0) {

        let { tl_Height, tl_strokeColor, tl_strokeWidth, tl_radius, tl_fillColor, pg_fillColor, isGradient } = this.CanvasConfigParams;

        // 绘制进度条
        if (!this._CanvasContent || !this.ParentNode) return false;
        let { width, height } = this.ParentNode.getBoundingClientRect();
        width = Math.floor(width - this.#CanvasMarginLeft);

        this.TimeLinePath = new Path2D();

        let roundLeft = 0;
        let ctx = this._CanvasContent;

        ctx.clearRect(roundLeft, (height / 2) - tl_Height / 2, width, tl_Height)
        ctx.save()
        ctx.beginPath();
        ctx.strokeStyle = tl_strokeColor || "red"
        ctx.lineWidth = tl_strokeWidth || 0;
        ctx.fillStyle = tl_fillColor || "#666"
        this.TimeLinePath.roundRect(roundLeft, (height / 2) - tl_Height / 2, width, tl_Height, tl_radius)
        ctx.closePath();
        ctx.fill(this.TimeLinePath);
        tl_strokeWidth && ctx.stroke(this.TimeLinePath);
        ctx.restore()

        // 绘制进度
        ctx.save()
        ctx.fillStyle = isGradient ? this.createGradient(roundLeft, (height / 2) - tl_Height / 2, progress, tl_Height) as CanvasGradient : pg_fillColor || "red"
        ctx.beginPath();
        ctx.roundRect(roundLeft, (height / 2) - tl_Height / 2, progress, tl_Height, tl_radius)
        ctx.fill();
        ctx.restore()
    }
    /**
     * 添加时间提示dom
     * @returns 
     */
    MakeReMindElement() {
        if (this.isCanvas) {
            this.#_MakeScaleCanvas()
        } else {
            this.#_MakeScaleElement()
        }
    }
    #_MakeScaleCanvas() {
        if (!this._CanvasContent || !this.ParentNode) return false;
        let ctx = this._CanvasContent;

        let { fontSize, scale_fontColor, scale_strokeColor, tl_Height, scale_lineWidth, scale_lineLength } = this.CanvasConfigParams;

        let { width, height } = this.ParentNode.getBoundingClientRect();
        width = width - this.#CanvasMarginLeft;
        // 绘制标尺
        this.TimeSlotWidth = width / this.ReviewNum;

        this.TimeSlotIntervalWidth = Number((this.TimeSlotWidth / this.TimeSlotInterval).toFixed(2))

        ctx.save()
        ctx.font = `${fontSize}px 微软雅黑`;
        for (let i = 0; i < this.ReviewNum; i++) {
            let x = (i * this.TimeSlotWidth * 1);

            let y = height / 2;
            ctx.strokeStyle = scale_strokeColor || "red"
            ctx.lineWidth = scale_lineWidth || 2
            ctx.beginPath();
            ctx.moveTo(x, y + tl_Height / 2)
            ctx.lineTo(x, y + tl_Height / 2 + scale_lineLength)

            let text = (this.CustomReMindLabelfn instanceof Function) ?
                this.CustomReMindLabelfn(this.MacroTextArray[i], this.DateTextArray[i]) :
                this.UnitArray[this.TimeLevel] + (Number(this.MacroTextArray[i]) + 1) + (this.DateTextArray[i] ? this.DateTextArray[i] : '')
            let { width: mt_width } = ctx.measureText(text)

            ctx.fillStyle = scale_fontColor || "#000"
            ctx.fillText(text, Math.max(0, x - mt_width / 2) && Math.min(width, x - mt_width / 2), y + 20)

            ctx.stroke();
        }
        ctx.restore()
    }
    #_MakeScaleElement() {
        let rect = this.getElementRectById("time_content");

        if (rect == null) return false;

        this.TimeSlotWidth = rect?.width / this.ReviewNum;

        this.TimeSlotIntervalWidth = Number((this.TimeSlotWidth / this.TimeSlotInterval).toFixed(2))

        let time_progressbar_remind = this.getByClass("time_progressbar_remind")[0];

        for (let i = 0; i < this.ReviewNum; i++) {
            let span = document.createElement("span");
            span.innerText = (this.CustomReMindLabelfn instanceof Function) ?
                this.CustomReMindLabelfn(this.MacroTextArray[i], this.DateTextArray[i]) :
                this.UnitArray[this.TimeLevel] + (Number(this.MacroTextArray[i]) + 1) + (this.DateTextArray[i] ? this.DateTextArray[i] : '')
            span.style.cssText = `width:${this.TimeSlotWidth}px;`
            time_progressbar_remind?.appendChild(span)
        }
    }
    // 自动播放的定时器id，方便清除定时器
    _setInterval: number = -1;
    /**
     * 自动修改时间轴状态
     * @param flag 
     */
    autoUpdateTimeStatus(flag: boolean) {
        let self = this;
        if (flag) {

            // 某个时间段内的进一步的值
            let IntervalWidth = this.TimeSlotIntervalWidth * this.TimeStepLength;
            if (this.TimeLevel == 2) {
                let curr_monthDay = this.getDaysByMonth(this.CurrentDay);

                IntervalWidth = curr_monthDay / this.TimeSlotWidth;
            }

            let len = self.CurrentTimeProgress + IntervalWidth;
            let totalLen = self.TimeSlotWidth * self.ReviewNum;
            if (len >= totalLen) len = 0;

            self.updataElementStatus(len)

            self._setInterval && clearInterval(self._setInterval);
            self._setInterval = setInterval(() => {
                self.autoUpdateTimeStatus(flag);
            }, self.TimeMoveSpeed)
        } else {
            clearInterval(self._setInterval)
        }
    }
    /**
     * 修改时间轴的位置-进度
     * @param PosiX 
     * @returns 
     */
    updataElementStatus(progress: number) {
        let _progress = progress;
        this.CurrentTimeProgress = _progress;
        this.updataShowTooltip(_progress)
    }
    /**
     * 定时器的id，
     * 控制tip元素的消失
     */
    _setTimeoutId: number = -1;
    /**
     * 更改tip元素样式
     * @param progress
     * @returns 
     */
    updataShowTooltip(progress: number) {

        let self = this;

        let _progress = progress;

        if (this.time_progressbar_tooltip == null) return false;

        let rect = self.getDateByOffsetX(_progress);

        let { isNotAchieve, length } = this.getLengthByDate(rect);

        if (isNotAchieve && this.isAdsorb) rect = self.getDateByOffsetX(length)

        this.time_progressbar_tooltip.innerHTML = (self.setTooltipElementFn instanceof Function && self.setTooltipElementFn(rect)) || `
            日期：${rect.day - 1}<br />
            时间：${rect.date}
        `

        let tooltip_rect = this.getElementRectById("time_progressbar_tooltip");

        if(this.isCanvas){
            this.drawTimeLineByCanvas(length);
        }else{
            if (this.t_progressbar) this.t_progressbar.style.cssText = `width:${length}px;`
        }

        (this.time_progressbar_tooltip).style.cssText = `z-index:999;width:7%;opacity:1;left:${length}px;top:-${(tooltip_rect.height) + 10}px`

        if (this._setTimeoutId != 0) clearTimeout(self._setTimeoutId);

        this._setTimeoutId = setTimeout(() => {
            clearTimeout(self._setTimeoutId)
            if (self.time_progressbar_tooltip == null) return false;
            (self.time_progressbar_tooltip).style.cssText = "opacity:0,z-index:-1;"
        }, 2000)
    }
    /**
     * @description 将长度转换为时间
     * @description 本长度的起点是指时间线0点距离，不是屏幕的0点
     * @param {*} offsetX
     */
    getDateByOffsetX(offsetX: number) {
        // 跨越的时间段
        let timeSolt = Math.floor(offsetX / this.TimeSlotWidth);
        // 剩余的时间段距离
        let _timeSolt = offsetX % this.TimeSlotWidth;

        let macro = this.MacroTextArray[Math.floor(timeSolt)];

        let day = this.DateTextArray[timeSolt] + 1;

        // 记录下当前走到哪里了
        this.CurrentDay = day;
        // 具体时间
        let date = Math.floor(_timeSolt / this.TimeSlotIntervalWidth);

        // 如果时间轴的层级是2，则因为月份会有不同，因此要使用另一种计算方法
        if (this.TimeLevel == 2) {

            let a = this.getDaysByMonth(this.DateTextArray[Math.floor(timeSolt)])
            let b = a / this.TimeSlotWidth;

            date = (Math.ceil(_timeSolt * b) % a) + 1;
        }

        return {
            macro,
            day,
            date
        }
    }
    /**
    * 将时间转换为长度
    */
    getLengthByDate({ macro, day, date }: { macro: string, day: number, date: number }) {
        // 计算宏观时间的总长度
        let macroTotal = 0;
        const _day = Number(day) - 1;
        
        // 计算在时间数组中的位置
        let timeSlotIndex = 0;
        for(let i = 0; i < this.DateTextArray.length; i++) {
            if(this.DateTextArray[i] === _day && 
               this.MacroTextArray[i] === String(macro)) {
                timeSlotIndex = i;
                break;
            }
        }
        
        // 计算宏观长度
        macroTotal = timeSlotIndex * this.TimeSlotWidth;
        
        // 计算具体时间的长度
        let timeTotal = 0;
        switch(this.TimeLevel) {
            case 0: // 分钟
                timeTotal = (date / 60) * this.TimeSlotWidth;
                break;
            case 1: // 小时
                timeTotal = (date / 24) * this.TimeSlotWidth;
                break;
            case 2: // 天
                const daysInMonth = this.getDaysByMonth(_day);
                timeTotal = (date / daysInMonth) * this.TimeSlotWidth;
                break;
            case 3: // 月
                timeTotal = (date / 12) * this.TimeSlotWidth;
                break;
        }
        
        // 计算总长度
        const totalLength = macroTotal + timeTotal;
        
        // 处理吸附效果
        if(this.isAdsorb) {
            const stepWidth = this.TimeSlotIntervalWidth * this.TimeStepLength;
            const steps = Math.round(totalLength / stepWidth);
            const snapLength = steps * stepWidth;
            
            return {
                isNotAchieve: Math.abs(totalLength - snapLength) > 1,
                length: snapLength
            };
        }
        
        return {
            isNotAchieve: false,
            length: totalLength
        };
    }
    /**
     * 设置显示的时间文本数组
     * 0级
     */
    setDateTextArrayZore() {

        let date = this.baseDate || new Date();

        // 月份
        let month = date.getMonth() + 1;
        // 小时
        let hours = date.getHours();

        this.MacroTextArray = []
        this.DateTextArray = []

        for (let i = 0; i < this.ReviewNum; i++) {
            this.MacroTextArray.push(month + '')
            this.DateTextArray.push(hours)
            hours += 1;
            if (hours == 24) {
                month++
                hours = 0;
            }
        }

    }
    /**
     * 设置显示的时间文本数组
     * 1级
     */
    setDateTextArrayOne() {

        let date = this.baseDate || new Date();
        // 周几
        let week = date.getDay();
        // 几号 ,因为下面会+1 因此这里要 -1
        let day = date.getDate() - 1;
        // 月份
        let month = date.getMonth() + 1;
        // 本月的天数
        let monthDay = this.getDaysByMonth(month);
        let _monthDay = 0;

        this.MacroTextArray = []
        this.DateTextArray = []

        for (let i = 0; i < this.ReviewNum; i++) {
            this.MacroTextArray.push(((week + i) % 7) + '')

            _monthDay++;
            // 避免月份出错
            if (_monthDay > monthDay) {
                month++
                monthDay = this.getDaysByMonth(month);
                _monthDay = 0;
            }
            this.DateTextArray.push(((day + i) % (monthDay)) + 1)
        }
    }
    /**
     * 设置显示的时间文本数组
     * 2级
     */
    setDateTextArrayTwo() {
        let date = this.baseDate || new Date();
        // 月份
        let month = date.getMonth() + 1;
        // 年份
        let year = date.getFullYear();

        this.MacroTextArray = []
        this.DateTextArray = []

        for (let i = 0; i < this.ReviewNum; i++) {
            this.MacroTextArray.push(year + '')
            this.DateTextArray.push(month)
            month += 1
            if (month == 13) {
                year++
                month = 1
            }
        }
    }
    /**
     * 设置显示的时间文本数组
     * 3级
     */
    setDateTextArrayThree() {
        let date = this.baseDate || new Date();
        // 年份
        let year = date.getFullYear();

        this.MacroTextArray = []
        this.DateTextArray = []

        for (let i = 0; i < this.ReviewNum; i++) {
            this.MacroTextArray.push(year + '')
            this.DateTextArray.push(0)
            year++
        }

    }
    /**
     * 通过月份来返回本月的时间
     * @param month 月份
     * @returns 本月的时间
     */
    getDaysByMonth(month: number) {
        let a = [1, 3, 5, 7, 8, 10, 12];
        let b = [2]
        if (a.includes(month)) {
            return 31
        } else if (b.includes(month)) {
            return this.#isLeapYear(this.baseDate?.getFullYear()) ? 29 : 28
        } else {
            return 30
        }
    }
    /**
     * 判断当前是否是闰年
     * @param year 
     * @returns 
     */
    #isLeapYear(year: number | undefined) {
        if (!year) return false;
        let _year = Number(year)
        return (_year % 4 == 0 && _year % 100 != 0) || (_year % 400 == 0) ? true : false
    }
    /**
     * 判断点是否在指定路径内
     */
    isPointInPath(...args: any[]) {
        if (!this.isCanvas || !this._CanvasContent) return true;
        let [path, x, y] = args;
        if (path instanceof Path2D) {
            return this._CanvasContent.isPointInPath(path, x, y);
        } else {
            return this._CanvasContent.isPointInPath(args[0], args[1]);
        }
    }
    /**
     * 生成渐变色
     * @param x0 起始点x
     * @param y0 起始点y
     * @param x1 结束点x
     * @param y1 结束点y
     * @returns 
     */
    createGradient(x0: number, y0: number, x1: number, y1: number) {
        let { pg_gradientMode, pg_gradientColors } = this.CanvasConfigParams;
        let gradient: CanvasGradient | null = this.makeGridentObjectByMode(pg_gradientMode, x0, y0, x1, y1);

        if (!gradient) return ''
        let average = 1 / pg_gradientColors.length;
        pg_gradientColors.forEach((item, index) => {
            gradient.addColorStop(average * index, item)
        })
        return gradient;
    }
    /**
     * 根据模式返回相关的渐变色对象
     */
    makeGridentObjectByMode(mode: GradientModeType, ...args: any[]): CanvasGradient | null {
        let [x0, y0, x1, y1] = args;

        let canvasGridentMode: GradientModeType[] = ['linear', 'radial', 'conic']

        if (!canvasGridentMode.includes(mode)) throw new Error(`渐变的模式必须是${canvasGridentMode.join(',')}的其中一种`)
        if (!this._CanvasContent) return null;
        let ctx = this._CanvasContent;
        // 计算中心点
        let center = {
            x: (x1 - x0) / 2,
            y: (y1 - y0) / 2
        }
        let result = null;
        switch (mode) {
            case "linear":
                result = ctx.createLinearGradient(x0, y0, x1, y1)
            case 'radial':
                result = ctx.createRadialGradient(x0, y0, 20, x1, y1, center.x)
            case 'conic':
                result = ctx.createConicGradient(0, center.x, center.y)
        }
        return result;
    }
    /**
     * 通过id查找元素
     * @param id 
     * @param flag 是否往时间轴最外层元素中找元素
     * @returns 
     */
    getById(id: string, flag = true) {
        let n = flag ? document : this.ParentNode;
        return n && (n as Document).getElementById(id);
    }
    /**
     * 通过class查找元素
     * @param className 
     * @returns 
     */
    getByClass(className: string) {
        if (this.ParentNode == null) return [];
        return this.ParentNode.getElementsByClassName(className);
    }
    /**
     * 通过id获取元素的具体信息
     * @param id 
     * @returns 
     */
    getElementRectById(id: string) {
        let e = this.getByClass(id);
        return e && e[0].getBoundingClientRect();
    }
    /**
     * 销毁时间线中实例和绑定的事件
     */
    DestoryTimeLine(flag?: boolean) {
        if (flag) return false;
        let time_progressbar = this.getByClass("time_progressbar")
        time_progressbar[0] && (time_progressbar[0] as HTMLElement).removeEventListener("mousedown", this.Time_MouseDown)
        window.removeEventListener("mousemove", this.WindowMouseMove_time)
        window.removeEventListener("mouseup", this.WindowMouseUp_time)

        // 删除自动播放开关的事件
        let time_switch = this.getByClass("time_switch")[0];
        (time_switch as HTMLDivElement).removeEventListener("click", this.timeSwitchClickHandle)

        this.setTooltipElementFn = null;
        // 将播放标识恢复初始化
        this.autoClickStatus = true;
        this.autoUpdateTimeStatus(false);
        // 将进度归零
        this.CurrentTimeProgress = 0;
        // 清空父元素
        if (this.ParentNode) this.ParentNode.innerHTML = "";
    }
}